#include "TestJsonData.h"
#include <json.hpp>
#include "../../core/CElapsedTimer.h"
#include "../../platform/PlatUtil.h"
#include "../../Cache.h"
#include "Util.h"

static const bool JsonData_Enabled = false;

static const CString JsonData_Dir = "D:/workplace_New/JsonData_V1_V2";
static const int JsonData_SendFrequencyMs = 16;

bool TestJsonData::s_isRecordingWindow = false;

void TestJsonData::parsingInBgThread() {
	if (!JsonData_Enabled || Config::TestCase_SampleDataEnabled)
		return;
	auto fileDirPath = JsonData_Dir;

	int lastSlashIndex = fileDirPath.lastIndexOf('/');
	auto prefixPath = fileDirPath.subString(0, lastSlashIndex + 1);
	auto dirName = fileDirPath.subString(lastSlashIndex + 1);
	CStringList dirNames;
	std::vector<CString> parts = dirName.split('_');
	for (int i = 1; i < parts.size(); i++)
		dirNames << parts[0] + "_" + parts[i];

	CUtil::loop([&, prefixPath, dirNames] {
		static CElapsedTimer timer;
		timer.reset();
		static int cnt = 0;
		if (s_isRecordingWindow && cnt == 1 || cnt == InvalidNum) {
			if (s_isRecordingWindow)
				LogI << ">>>>>> grab window images completed! <<<<<<";
			s_isRecordingWindow = false;
			cnt = InvalidNum;
			return;
		}

		for (auto& dir : dirNames)
			readingJsonFiles(prefixPath + dir);

		auto deltaMs = timer.elapsed();
		int milliseconds = deltaMs % 1000;
		int seconds = (deltaMs / 1000) % 60;
		int minutes = (deltaMs / (1000 * 60)) % 60;
		LogI << "########## Recycle datas round #" << ++cnt << ", spend " << minutes << "m," << seconds << "s," << milliseconds << "ms";
	}, 0);
}

void TestJsonData::readingJsonFiles(const CString& dirPath) {
	std::vector<std::string> fileNames;
	PlatUtil::filesOfDir(fileNames, dirPath);
	for (auto& fileName : fileNames) {
		parseJsonFile(dirPath + "/" + fileName);
		CUtil::msleep(JsonData_SendFrequencyMs);
	}
}

void TestJsonData::parseJsonFile(const CString& filePath) {
#if false
	LogD << "##################### parsing: " << filePath;
#endif
	std::string jsonData;
	PlatUtil::readFileAsString(jsonData, filePath);
	const auto& jsonDoc = nlohmann::json::parse(jsonData);

	/******************************* Models ********************************/
	/******************************* Models ********************************/
	const auto& objectList = jsonDoc["object_list"];
	int objNum = objectList["obj_num"].get<int>();

	CVector<ModelArg> modelArgs;
	const auto& objects = objectList["objects"];
	for (const auto& obj : objects) {
		int identification = obj["idt"].get<int>();

		ModelArg arg;
		int probability = obj["prob"].get<int>();
		if (probability <= 0)// invalid data
			continue;
		int ID = obj["id"].get<int>();
		if (ID <= 0)// invalid data
			continue;
		arg.identified = kt::Util::isIdentified(identification);
		if (!arg.identified) {
			modelArgs << arg;
			continue;
		}
		int objClass = obj["cls"].get<int>();
		float hDist = obj["d_lat"].get<float>();// y
		float vDist = obj["d_lon"].get<float>();// x
		float hSpeed = obj["v_lat"].get<float>();
		float vSpeed = obj["v_lon"].get<float>();
		float angle = obj["yawang"].get<float>();// unit: radians
		float width = obj["wid"].get<float>();
		float length = obj["len"].get<float>();
		//int blinker = obj["blnk"].get<int>();
		//int brake = obj["brk"].get<int>();
		int dynamicProp = obj["dyn"].get<int>();
		int oncoming = obj["onc"].get<int>();
		int trackingState = 0;
		int objectColour = 0;
		if (obj.contains("trck"))// c++17
			trackingState = obj["trck"].get<int>();// latest old version: field = "following_mode"/"tracking_state"
		if (obj.contains("clr"))
			objectColour = obj["clr"].get<int>();// latest old version: no the field

		ModelType modelType = kt::Util::modelType(objClass);
		P pos = kt::Util::modelPos(hDist, vDist);
		bool isAccTracking = kt::Util::isAccTracking(trackingState);
		bool isOncoming = kt::Util::isOncoming(oncoming);
		CColor objColor = kt::Util::modelColor(objectColour);
		MoveStatus moveStatus = kt::Util::moveStatus(dynamicProp);

		arg.ID = ID;
		arg.type = modelType;
		arg.pos = pos;
		arg.angle = angle;
		arg.isOncoming = isOncoming;
		arg.color = objColor;
		arg.isAccTracking = isAccTracking;
		arg.width = width;
		arg.length = length;
		arg.relSpeed = kt::Util::relSpeed(hSpeed, vSpeed);
		arg.probability = probability;
		arg.moveStatus = moveStatus;
		modelArgs << arg;
	}
	Cache::recvModels(modelArgs);

	/******************************* Lines ********************************/
	/******************************* Lines ********************************/
	const auto& laneLines = jsonDoc["lane_lines"];
	int lineNum = laneLines["l_n"].get<int>();
	const auto& laneChange = laneLines["l_chg"];
	int direction = laneLines["dir"].get<int>();
	
	auto alc = kt::Util::alc(laneChange[0].get<int>(), laneChange[1].get<int>());
	auto dclc = kt::Util::dclc(direction);
	Cache::updateALC(alc);
	Cache::updateDCLC(dclc);

	CVector<LineArg> lineArgs;
	const auto& lines = laneLines["lines"];
	for (const auto& line : lines) {
		int identification = line["idt"].get<int>();

		LineArg arg;
		int probability = line["prob"].get<int>();
		if (probability <= 0)// invalid data
			continue;
		const auto& pointList = line["lst"];
		auto start = pointList[0].get<float>();
		auto end = pointList[1].get<float>();
		if (start >= end)// invalid data
			continue;
		arg.identified = kt::Util::isIdentified(identification);
		if (!arg.identified) {
			lineArgs << arg;
			continue;
		}
		int ID = line["id"].get<int>();
		int type = line["typ"].get<int>();
		int colour = line["clr"].get<int>();
		bool isCrossing = kt::Util::isCrossing(line["crs"].get<int>());

		auto C = CVector<float>() << pointList[2].get<float>() << pointList[3].get<float>() << pointList[4].get<float>() << pointList[5].get<float>();
		arg.eq = kt::Util::lineEq(C, start, end);
		arg.style = kt::Util::lineStyle(type);
		arg.color = kt::Util::lineColor(colour);
		arg.isCrossing = isCrossing;
		arg.probability = probability;
		lineArgs << arg;
	}
	Cache::recvLines(lineArgs);
}